﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using HtmlAgilityPack;
using System.Threading;
using System.Net;
using System.IO;
using System.IO.Compression;


namespace BolorToli
{
    public partial class Main : Form
    {
        //private const string URL_PATTERN = "http://www.bolor-toli.com/index.php?pageId=10&direction=mn-en&search={0}";
        //private const string URL_PATTERN = "http://www.j-kosen.info/bolortoli/search.php?value={0}";
        private const string URL_PATTERN = "http://mobile.bolor-toli.com/index.php?pageId=10&direction=mn-en&search={0}";

        private DataTable exactResult;
        private DataTable similarResult;

        private HtmlAgilityPack.HtmlDocument document;
        private bool m_Exit = false; //form_closing эвент дээр програмаас гарч байгаа эсэхийг шалгах
        private bool m_firstClose = true;
        private int m_ResultNotifMaxCount = 5;

        public Main()
        {
            InitializeComponent();

            exactResult = new DataTable();
            exactResult.Columns.Add("key", typeof(string));
            exactResult.Columns.Add("value", typeof(string));

            similarResult = new DataTable();
            similarResult.Columns.Add("key", typeof(string));
            similarResult.Columns.Add("value", typeof(string));

            document = new HtmlAgilityPack.HtmlDocument();
        }

        private void searchButton_Click(object sender, EventArgs e)
        {
            DateTime start = DateTime.Now;
            try
            {
                this.Cursor = Cursors.WaitCursor;

                searchButton.Enabled = false;

                exactResult.Rows.Clear();
                similarResult.Rows.Clear();

                if (wordTextBox.Text.Trim().Length == 0) return;

                HttpWebRequest request = WebRequest.Create(string.Format(URL_PATTERN, wordTextBox.Text.Trim())) as HttpWebRequest;
                request.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip");

                HttpWebResponse response = request.GetResponse() as HttpWebResponse;
                if (response.StatusCode != HttpStatusCode.OK) return;

                StreamReader reader = new StreamReader(new GZipStream(response.GetResponseStream(), CompressionMode.Decompress));
                document.LoadHtml(reader.ReadToEnd());

                Thread exactResultThread = new Thread(new ThreadStart(ProcExactResult));
                exactResultThread.Start();

                Thread similarResultThread = new Thread(new ThreadStart(ProcSimilarResult));
                similarResultThread.Start();

                response.Close();

                exactResultThread.Join();
                similarResultThread.Join();
            }
            catch (Exception exception)
            {
                MessageBox.Show(exception.Message);
            }
            finally
            {
                exactResultGridView.DataSource = exactResult;
                exactResultTabPage.Text = string.Format("««« EXACT RESULTS ({0}) »»»", exactResult.Rows.Count);

                similarResultGridView.DataSource = similarResult;
                similarResultTabPage.Text = string.Format("««« SIMILAR RESULTS ({0}) »»»", similarResult.Rows.Count);

                wordTextBox.SelectAll();

                searchButton.Enabled = true;

                this.Cursor = Cursors.Default;

                this.Text = string.Format("Bolor Toli - {0} second(s)", DateTime.Now.Subtract(start).TotalSeconds);
            }
        }

        private void ProcExactResult()
        {
            StringBuilder notifResult = new StringBuilder();
            try
            {
                HtmlNode rootNode = document.GetElementbyId("wtbl1");
                if (rootNode == null) return;

                if (rootNode.ChildNodes.Count <= 1) return;
                rootNode.ChildNodes.Remove(0);

                DataRow row = null;
                int i = 0;
                foreach (HtmlNode node in rootNode.ChildNodes)
                {
                    row = exactResult.NewRow();
                    row["key"] = node.ChildNodes[1].InnerText.Replace("&nbsp;", " ").TrimEnd();
                    row["value"] = node.ChildNodes[2].InnerText.Replace("&nbsp;", " ").TrimEnd();
                    exactResult.Rows.Add(row);

                    if (i < m_ResultNotifMaxCount)
                    {
                        notifResult.AppendLine(string.Format("{0} - {1}", row["key"], row["value"]));
                    }
                    else if (i == m_ResultNotifMaxCount)
                    {
                        notifResult.AppendLine("...");
                    }
                    i++;
                }
            }
            finally
            {
                if (!this.Visible)
                {
                    if (notifResult.Length > 0)
                        this.notifyIcon1.BalloonTipText = notifResult.ToString();
                    else
                        this.notifyIcon1.BalloonTipText = string.Format("no result for \"{0}\"", wordTextBox.Text);

                    this.notifyIcon1.ShowBalloonTip(1);
                }
            }
        }
        private void ProcSimilarResult()
        {
            HtmlNode rootNode = document.GetElementbyId("wtbl2");
            if (rootNode == null) return;

            if (rootNode.ChildNodes.Count <= 1) return;
            rootNode.ChildNodes.Remove(0);

            DataRow row = null;
            foreach (HtmlNode node in rootNode.ChildNodes)
            {
                row = similarResult.NewRow();
                row["key"] = node.ChildNodes[1].InnerText.Replace("&nbsp;", " ").TrimEnd();
                row["value"] = node.ChildNodes[2].InnerText.Replace("&nbsp;", " ").TrimEnd();
                similarResult.Rows.Add(row);
            }
        }

        private void wordTextBox_Enter(object sender, EventArgs e)
        {
            wordTextBox.SelectAll();
        }
        private void wordTextBox_MouseClick(object sender, MouseEventArgs e)
        {
            wordTextBox.SelectAll();
        }

        private void Main_Activated(object sender, EventArgs e)
        {
            wordTextBox.Focus();
        }

        private void Main_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (!m_Exit)
            {
                e.Cancel = true;
                Visible = false;

                if (m_firstClose)
                {
                    this.notifyIcon1.BalloonTipText = "I'm here";
                    this.notifyIcon1.ShowBalloonTip(1);
                    m_firstClose = false;
                }
            }
            else
            {
                UnregisterClipboardViewer();
            }
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show(this, "Are you sure you want to exit?"
                , "Bolor toli", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes)
            {
                m_Exit = true;
                this.Close();
            }
        }

        private void notifyIcon1_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                Visible = !Visible;
            }
            //Clipboard.ContainsText(TextDataFormat.Text));
        }

        private void showToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Visible = !Visible;
        }

        private void Main_VisibleChanged(object sender, EventArgs e)
        {
            if (Visible)
                showToolStripMenuItem.Text = "Hide";
            else
                showToolStripMenuItem.Text = "Show";
        }

        #region [ ClipBoard ]

        IntPtr m_ClipboardViewerNext;
        public class ClipBoardChangedEventHandler : EventArgs
        {
            public string CBText { get; private set; }

            public ClipBoardChangedEventHandler(string clipText)
            {
                CBText = clipText;
            }
        }

        event EventHandler<ClipBoardChangedEventHandler> OnClipBoardChanged;
        //private bool m_ReallyClipBoardChanged = false;

        private void RegisterClipboardViewer()
        {
            m_ClipboardViewerNext = Win32.User32.SetClipboardViewer(this.Handle);
        }
        /// <summary>
        /// Remove this form from the Clipboard Viewer list
        /// </summary>
        private void UnregisterClipboardViewer()
        {
            Win32.User32.ChangeClipboardChain(this.Handle, m_ClipboardViewerNext);
        }

        private void GetClipboardData()
        {
            if (Clipboard.ContainsText() && OnClipBoardChanged != null)
            {
                string text = Clipboard.GetText();
                OnClipBoardChanged.Invoke(this, new ClipBoardChangedEventHandler(text));
            }
        }

        void Main_OnClipBoardChanged(object sender, Main.ClipBoardChangedEventHandler e)
        {
            wordTextBox.Text = e.CBText;
            searchButton_Click(this, null);
        }

        #endregion

        protected override void WndProc(ref Message m)
        {
            switch ((Win32.Msgs)m.Msg)
            {
                case Win32.Msgs.WM_DRAWCLIPBOARD:
                    // Handle clipboard changed

                    GetClipboardData();

                    //
                    // Each window that receives the WM_DRAWCLIPBOARD message 
                    // must call the SendMessage function to pass the message 
                    // on to the next window in the clipboard viewer chain.
                    //
                    Win32.User32.SendMessage(m_ClipboardViewerNext, m.Msg, m.WParam, m.LParam);
                    break;

                case Win32.Msgs.WM_CHANGECBCHAIN:
                    //
                    // The WM_CHANGECBCHAIN message is sent to the first window 
                    // in the clipboard viewer chain when a window is being 
                    // removed from the chain. 
                    //

                    // When a clipboard viewer window receives the WM_CHANGECBCHAIN message, 
                    // it should call the SendMessage function to pass the message to the 
                    // next window in the chain, unless the next window is the window 
                    // being removed. In this case, the clipboard viewer should save 
                    // the handle specified by the lParam parameter as the next window in the chain. 

                    //
                    // wParam is the Handle to the window being removed from 
                    // the clipboard viewer chain 
                    // lParam is the Handle to the next window in the chain 
                    // following the window being removed. 
                    if (m.WParam == m_ClipboardViewerNext)
                    {
                        //
                        // If wParam is the next clipboard viewer then it
                        // is being removed so update pointer to the next
                        // window in the clipboard chain
                        //
                        m_ClipboardViewerNext = m.LParam;
                    }
                    else
                    {
                        Win32.User32.SendMessage(m_ClipboardViewerNext, m.Msg, m.WParam, m.LParam);
                    }

                    break;
                default:
                    base.WndProc(ref m);
                    break;
                // ... 
            }
        }

        private void Main_Load(object sender, EventArgs e)
        {
            OnClipBoardChanged += new EventHandler<ClipBoardChangedEventHandler>(Main_OnClipBoardChanged);
        }

        private void toolStripMenuCatchClipboard_CheckedChanged(object sender, EventArgs e)
        {
            if (toolStripMenuCatchClipboard.Checked)
            {
                RegisterClipboardViewer();
            }
            else
            {
                UnregisterClipboardViewer();
            }
        }

        private void toolStripMenuCatchClipboard_Click(object sender, EventArgs e)
        {
            toolStripMenuCatchClipboard.Checked = !toolStripMenuCatchClipboard.Checked;
        }

        private void notifyIcon1_BalloonTipClicked(object sender, EventArgs e)
        {
            this.Visible = true;
        }
    }
}
